
#include "desktop.h"
#include "desktop_data.h"

#include <unistd.h>
#include <sys/types.h>  /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#define __USE_MISC 1
#include <net/if.h>
#include <arpa/inet.h>    /* inet(3) functions */
#include <sys/epoll.h>    /* epoll function */
#include <fcntl.h>        /* nonblocking */
#include <sys/resource.h> /*setrlimit */
#include <errno.h>
#include <sys/time.h>
#include <sys/ioctl.h>

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>

#define MAXLINE 256
#define MAX_MESSAGE_LENGTH 1200
#define MAX_TCPC_CLIENT 10

unsigned char checksum(const unsigned char *buf, int len)
{
    int iSum = 0;
    int i = 0;
    for (i = 0; i < len; i++)
    {
        iSum += buf[i];
    }
    iSum %= 0x100; // 也可以&0xff
    return (unsigned char)iSum;
}

int word2Int(char *data)
{
    return (data[0] << 8 | data[1]);
}

int get_local_mac(const char *if_name, char *local_mac)
{
    int sock;
    int i = 0;
    struct ifreq ifr;

    bzero(&ifr, sizeof(struct ifreq));
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket error !");
        return -1;
    }

    strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);

    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
    {
        perror("ioctl error !");
        close(sock);
        return -1;
    }
    for (i = 0; i < 6; ++i)
    {
        local_mac[i] = ifr.ifr_hwaddr.sa_data[i];
    }
    close(sock);
    return 0;
}

int set_local_mac(const char *if_name, char *local_mac)
{
    int sockfd;
    struct ifreq req;

    char buf[32] = {0};
    int i = 0;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("fail to create socket ..!");
        return -1;
    }
    strcpy(req.ifr_ifrn.ifrn_name, if_name);
    if (ioctl(sockfd, SIOCGIFHWADDR, &req) < 0)
    {
        perror("fail to get ioctl ");
        close(sockfd);
        return -1;
    }
    memcpy(buf, req.ifr_ifru.ifru_hwaddr.sa_data, 6);
    for (i = 0; i < 6; i++)
        printf("%02x:", buf[i] & 0xff);
    puts("\b ");

    memcpy(req.ifr_ifru.ifru_hwaddr.sa_data, local_mac, 6);
    for (i = 0; i < 6; i++)
        printf("%02x:", req.ifr_ifru.ifru_hwaddr.sa_data[i] & 0xff);
    /* *设置MAC地址 */
    if (ioctl(sockfd, SIOCSIFHWADDR, &req) < 0)
    {
        perror("fail to ioctl ");
        close(sockfd);
        return -1;
    }
    close(sockfd);
    return 1;
}

int change_localtime(int8_t timezone)
{
    if (timezone < -12 || timezone > 12)
        return 0;
    char zoneFile[64] = {0};
    char cmd[128] = {0};
    memset(zoneFile, 0, 64);
    memset(cmd, 0, 128);
    strcpy(zoneFile, timezone_Table[timezone + 12]);
    if (access(zoneFile, F_OK) == -1)
    {
        return 0;
    }
    sprintf(cmd, "wr ln -sf %s /etc/localtime\0", zoneFile);
    system("wr rm -rf /etc/localtime");
    system(cmd);
    printf("%s\n", cmd);
    return 1;
}

static int setnonblocking(int sockfd)
{
    if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0) | O_NONBLOCK) == -1)
    {
        return -1;
    }
    return 0;
}

void desktop_run(cfg_pu_t *pu)
{
    char m_ip[32] = {0};
    char m_port[8] = {0};

    int listenq = 1024;
    int listenfd, connfd, kdpfd, nfds, n, nread, curfds;
    struct sockaddr_in servaddr, cliaddr;
    socklen_t socklen = sizeof(struct sockaddr_in);
    struct epoll_event ev;
    struct epoll_event events[MAX_TCPC_CLIENT];
    struct rlimit rt;
    // char buf[MAXLINE];

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;

    servaddr.sin_addr.s_addr = inet_addr(g_cfg->g_basic->ip);
    servaddr.sin_port = htons(60000);
    strcpy(m_ip, g_cfg->g_basic->ip);
    sprintf(m_port, "%d\0", 60000);
    // }
    int flags = SOCK_STREAM;

#ifdef SOCK_CLOEXEC
    flags |= SOCK_CLOEXEC;
#endif
    listenfd = socket(PF_INET, flags, IPPROTO_TCP);
    if (listenfd == -1)
    {
        UTIL_LOG_E(pu, "can't create socket file");
        pthread_exit(NULL);
    }

    int opt = 1;
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
                   (char *)&opt, sizeof(opt)) == -1)
    {
        close(listenfd);
        pthread_exit(NULL);
    }

    if (setnonblocking(listenfd) < 0)
    {
        UTIL_LOG_E(pu, "setnonblock error");
    }

    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) == -1)
    {
        UTIL_LOG_E(pu, "bind %s:%s error,%s", m_ip, m_port, strerror(errno));
        close(listenfd);
        pthread_exit(NULL);
    }

    // 主进程关闭后，同时关闭socket
    fcntl(listenfd, F_SETFD, FD_CLOEXEC);

    if (listen(listenfd, listenq) == -1)
    {
        UTIL_LOG_E(pu, "listen error");
        close(listenfd);
        pthread_exit(NULL);
    }

    /*创建epoll句柄，把监听 socket 加入到 epoll 集合里 */
    kdpfd = epoll_create(MAX_TCPC_CLIENT);
    ev.events = EPOLLIN | EPOLLET;
    ev.data.fd = listenfd;
    if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0)
    {
        UTIL_LOG_E(pu, "epoll set insertion error: fd=%d", listenfd);
        pthread_exit(NULL);
    }

    curfds = 1;
    UTIL_LOG_D(pu, "epollserver:%s.%s startup\n", m_ip, m_port);
    for (;;)
    {
        /* 等待有事件发生 */
        nfds = epoll_wait(kdpfd, events, curfds, -1);
        if (nfds == -1)
        {
            UTIL_LOG_E(pu, "epoll_wait error");
            continue;
        }

        /* 处理所有事件 */
        for (n = 0; n < nfds; ++n)
        {
            if (events[n].data.fd == listenfd)
            {
                connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &socklen);

                if (connfd < 0)
                {
                    UTIL_LOG_E(pu, "accept error");
                    continue;
                }
                UTIL_LOG_D(pu, "60000 accept form %s:%d", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
                // pu->hanlder.param = inet_ntoa(cliaddr.sin_addr);
                if (curfds >= MAX_TCPC_CLIENT)
                {
                    UTIL_LOG_E(pu, "too many connection, more than %d", MAX_TCPC_CLIENT);
                    close(connfd);
                    continue;
                }

                if (setnonblocking(connfd) < 0)
                {
                    UTIL_LOG_E(pu, "setnonblocking error");
                    close(connfd);
                    continue;
                }

                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = connfd;

                if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < 0)
                {
                    UTIL_LOG_E(pu, "add socket '%d' to epoll failed: %s", connfd, strerror(errno));
                    close(connfd);
                    continue;
                }

                // 加入新的socket
                pu_param_t *param = (pu_param_t *)pu->hanlder.param;
                strncpy(param->destIp, inet_ntoa(cliaddr.sin_addr), 32);

                tcps_t *new = malloc(sizeof(tcps_t));
                new->len = 0;
                new->s = connfd;

                new->debug = param->debug;
                rt_slist_append(&param->socket60000, &new->slist);

                curfds++;
                continue;
            }

            // 处理客户端请求
            if (handle(pu, events[n].data.fd) < 0)
            {
                epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd, &ev);
                curfds--;

                pu_param_t *param = (pu_param_t *)pu->hanlder.param;
                rt_slist_t *e;
                pthread_mutex_lock(&param->lock);
                rt_slist_for_each(e, &param->socket60000)
                {
                    tcps_t *socket = rt_slist_entry(e, tcps_t, slist);
                    if (socket->s == events[n].data.fd)
                    {
                        param->socket60000 = *rt_slist_remove(&param->socket60000, &socket->slist);
                        free(socket);
                    }
                }
                pthread_mutex_unlock(&param->lock);
            }
        }
    }

    close(listenfd);
    pthread_exit(NULL);
}

static int handle(cfg_pu_t *pu, int connfd)
{
    int nread;
    uint8_t req[MAX_MESSAGE_LENGTH];
    uint8_t rsp[MAX_MESSAGE_LENGTH];

    static char filename_buff[50] = "";

    nread = read(connfd, req, MAX_MESSAGE_LENGTH); // 读取客户端socket流

    if (nread == 0)
    {
        printf("60000 client %d close the connection\n", connfd);
        close(connfd);
        auto_stop();
        return -1;
    }
    else if (nread < 0)
    {
        perror("60000 read error");
        close(connfd);
        auto_stop();
        return -1;
    }
    else
    {
        util_hex_print(req, nread);

        // 判断是否已经收到注册包，从而绑定su
        pu_param_t *param = (pu_param_t *)pu->hanlder.param;
        rt_slist_t *e;
        pthread_mutex_lock(&param->lock);
        rt_slist_for_each(e, &param->socket60000)
        {
            tcps_t *ctx = rt_slist_entry(e, tcps_t, slist);
            if (ctx->s == connfd)
            {
                if (nread > 14) // header 3; version 2; msgno 2; ctrl 2; cmd 2; dalalen 2; data n; crc 1
                {
                    if (req[0] == 0xAA && req[1] == 0xBB && req[2] == 0x55)
                    {
                        uint8_t ver_hi = req[3];
                        uint8_t ver_lo = req[4];
                        uint8_t msgno_hi = req[5];
                        uint8_t msgno_lo = req[6];
                        int ctrl = word2Int(req + 7);
                        int cmd = word2Int(req + 9);
                        int datalen = word2Int(req + 11);
                        int dataCmd = 0;
                        LOG_I("SWJ", "---->>> Ctrl: %d, E_CMD: %d, DataLen: %d \n", ctrl, cmd, datalen);
                        if (datalen == 0)
                            continue;

                        if (datalen + 14 != nread)
                            continue;
                        uint8_t checkResult = checksum(req, nread - 1);
                        if (checkResult != req[nread - 1])
                        {
                            LOG_E("SWJ", "check error\n");
                            continue;
                        }
                        memcpy(rsp, req, 11);
                        dataCmd = req[13];

                        switch (cmd)
                        {
                        case 0x0002:
                            if (dataCmd == 0)
                                get_time(pu, ctx, rsp);
                            else if (dataCmd == 1)
                                set_time(pu, ctx, req, nread, rsp);
                            break;
                        case 0x0004:
                            if (dataCmd == 0)
                                get_sn(pu, ctx, rsp);
                            else if (dataCmd == 1)
                                set_sn(pu, ctx, req, nread, rsp);
                            break;
                        case 0x0005:
                            if (dataCmd == 0)
                                get_devtype(pu, ctx, rsp);
                            else if (dataCmd == 1)
                                set_devtype(pu, ctx, req, nread, rsp);
                            break;
                        case 0x0006:
                            if (dataCmd == 0)
                                enter_test_mode(pu, ctx, rsp);
                            else if (dataCmd == 1)
                                exit_test_mode(pu, ctx, rsp);
                            break;
                        case 0x0007:
                            if (dataCmd == 0)
                                get_timezone(pu, ctx, rsp);
                            else if (dataCmd == 1)
                                set_timezone(pu, ctx, req, nread, rsp);
                            break;
                        case 0x0008:
                            // set_do(pu, ctx, req, nread, rsp);
                            break;
                        case 0x0009:
                            send_heart(pu, ctx, rsp);
                            break;
                        case 0x000B:
                            // get_dio_ai(pu, ctx, rsp);
                            break;
                        case 0x000C:
                            sys_reboot(pu, ctx, rsp);
                            break;
                        case 0x000E:
                            get_topo(pu, ctx, rsp);
                            break;
                        case 0x000F:
                            if (dataCmd == 0)
                                get_dev_status(pu, ctx, rsp);
                            else
                                get_dev_data(pu, ctx, req, nread, rsp);
                            break;
                        case 0x0011:
                            // get_net_state(pu, ctx, rsp);
                            break;
                        case 0x0012:
                            get_trans_state(pu, ctx, rsp);
                            break;
                        case 0x0013:
                            get_collect_state(pu, ctx, rsp);
                            break;
                        case 0x0014:
                            if (dataCmd == 0)
                                get_macaddr(pu, ctx, rsp);
                            else if (dataCmd == 1)
                                set_macaddr(pu, ctx, req, nread, rsp);
                            break;
                        case 0x0040:
                            get_file_info(pu, ctx, rsp);
                            break;
                        case 0x0050:
                        {
                            if (dataCmd == 0x00)
                            {
                                char filename[50] = "";
                                if (0 < reply_file_cmd0(pu, ctx, req, nread, rsp, filename))
                                {
                                    reply_file_data(pu, ctx, req, nread, rsp, filename);
                                }
                            }
                            else if (dataCmd == 0x02) // recv file buff from swj
                            {
                                recv_file_data(pu, ctx, req, nread, rsp, filename_buff);
                            }
                            else if (dataCmd == 0x04)
                            {
                                reply_file_cmd4(pu, ctx, req, nread, rsp, filename_buff);
                            }
                            break;
                        }
                        default:
                            break;
                        }
                    }
                }
            }
        }
        pthread_mutex_unlock(&param->lock);
    }

    return 0;
}

static int send_heart(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 29;
    int i = 0;
    int snLen = strlen(g_cfg->g_basic->product);
    uint8_t checkResult = 0;
    float cpu = util_hw_get_cpu_usage();
    int sendcpu = (int)(cpu * 100);
    time_t sec;
    time(&sec);
    struct tm *ptm;
    ptm = localtime(&sec);

    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    // data_cmd
    msg[msg_length++] = 0x01;
    // res
    // msg[msg_length++] = 0x01;
    // SN
    if (snLen > 20)
    {
        for (i = 0; i < 20; i++)
        {
            msg[msg_length++] = g_cfg->g_basic->product[i];
        }
    }
    else
    {
        for (i = 0; i < snLen; i++)
        {
            msg[msg_length++] = g_cfg->g_basic->product[i];
        }
        for (i = snLen; i < 20; ++i)
        {
            msg[msg_length++] = '\0';
        }
    }
    // time
    msg[msg_length++] = (ptm->tm_year % 100);
    msg[msg_length++] = ptm->tm_mon + 1;
    msg[msg_length++] = ptm->tm_mday;
    msg[msg_length++] = ptm->tm_hour;
    msg[msg_length++] = ptm->tm_min;
    msg[msg_length++] = ptm->tm_sec;
    // cpu
    msg[msg_length++] = sendcpu >> 8;
    msg[msg_length++] = sendcpu & 0xff;
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_time(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 9;
    int i = 0;
    uint8_t checkResult = 0;
    time_t sec;
    time(&sec);
    struct tm *ptm;
    ptm = localtime(&sec);

    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    // data_cmd
    msg[msg_length++] = 0x00;
    // time
    msg[msg_length++] = (ptm->tm_year + 1900) >> 8;
    msg[msg_length++] = (ptm->tm_year + 1900) & 0xFF;
    msg[msg_length++] = ptm->tm_mon + 1;
    msg[msg_length++] = ptm->tm_mday;
    msg[msg_length++] = ptm->tm_hour;
    msg[msg_length++] = ptm->tm_min;
    msg[msg_length++] = ptm->tm_sec;
    msg[msg_length++] = ptm->tm_wday;
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    return tcps_write(pu, ctx, msg, msg_length);
}

static int set_time(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg)
{
    if (nlen < 23)
        return -1;
    int msg_length = 13;
    int size = 2;
    int i = 0;
    int result = 0;
    uint8_t checkResult = 0;
    struct tm ptm;

    int year = word2Int(req + 14);
    if (year < 2000)
        return -1;
    ptm.tm_year = year - 1900;
    ptm.tm_mon = req[16] - 1;
    ptm.tm_mday = req[17];
    ptm.tm_hour = req[18];
    ptm.tm_min = req[19];
    ptm.tm_sec = req[20];
    ptm.tm_wday = req[21];

    if (change_localtime(8) == 1)
    {
        printf("desktop set time: %d-%02d-%02d %02d:%02d:%02d\n", year, ptm.tm_mon + 1, ptm.tm_mday, ptm.tm_hour, ptm.tm_min, ptm.tm_sec);
        result = util_hw_set_systime(mktime(&ptm));
    }

    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    msg[msg_length++] = 0x01;
    if (result > 0)
        msg[msg_length++] = 0x01;
    else
        msg[msg_length++] = 0x01;
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_timezone(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 2;
    int i = 0;
    uint8_t checkResult = 0;
    time_t time_utc = 0;
    struct tm *p_tm_time;
    int time_zone = 0;

    p_tm_time = localtime(&time_utc); // 转成当地时间
    time_zone = (p_tm_time->tm_hour > 12) ? (p_tm_time->tm_hour -= 24) : p_tm_time->tm_hour;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    // data_cmd
    msg[msg_length++] = 0x00;
    // timezone
    msg[msg_length++] = time_zone;
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    return tcps_write(pu, ctx, msg, msg_length);
}

static int set_timezone(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg)
{
    if (nlen < 16)
        return -1;
    int msg_length = 13;
    int size = 9;
    int i = 0;
    int result = 1;
    uint8_t checkResult = 0;
    time_t time_utc = 0;
    struct tm *p_tm_time;
    // int time_zone = 0;
    int8_t getzone = 0;

    p_tm_time = localtime(&time_utc); // 转成当地时间
    // time_zone = (p_tm_time->tm_hour > 12) ? (p_tm_time->tm_hour -= 24) : p_tm_time->tm_hour;
    getzone = req[14];
    printf("desktop set timezone: %d\n", getzone);
    result = change_localtime(getzone);
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    msg[msg_length++] = 0x01;
    msg[msg_length++] = result;
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_macaddr(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 8;
    int i = 0;
    uint8_t checkResult = 0;
    char macAddr[6];
    if (get_local_mac("eth0", macAddr) == 0)
    {
        msg[11] = size >> 8;
        msg[12] = size & 0xFF;
        msg[msg_length++] = 0x01;
        msg[msg_length++] = 0x01;
        msg[msg_length++] = macAddr[0];
        msg[msg_length++] = macAddr[1];
        msg[msg_length++] = macAddr[2];
        msg[msg_length++] = macAddr[3];
        msg[msg_length++] = macAddr[4];
        msg[msg_length++] = macAddr[5];
        checkResult = checksum(msg, msg_length);
        msg[msg_length++] = checkResult;
        // util_hex_print(msg, msg_length);
        return tcps_write(pu, ctx, msg, msg_length);
    }
    else
    {
        return -1;
    }
}

void float_to_hex(float value, unsigned char *hex_array)
{
    union
    {
        float f;
        unsigned char bytes[4];
    } converter;

    converter.f = value;
    hex_array[0] = converter.bytes[0]; // 高位字节
    hex_array[1] = converter.bytes[1];
    hex_array[2] = converter.bytes[2];
    hex_array[3] = converter.bytes[3]; // 低位字节
}

static int get_dev_data(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg)
{
    int size = 0;

    LOG_W("SWJ", "----------------get dev data-------------\n");
    int msg_length = 57;
    uint8_t checkResult = 0;
    uint16_t req_datalen = word2Int(req + 11);

    char portname[20] = {0};
    char devname[20] = {0};

    uint8_t valindex_start = 0;
    uint8_t valindex_sum = 0;

    int i,j;
    for (i = 0; i < 20; i++)
    {
        portname[i] = req[14 + i];
        msg[15 + i] = req[14 + i];
    }

    for (i = 0; i < 20; i++)
    {
        devname[i] = req[34 + i];
        msg[35 + i] = req[34 + i];
    }

    valindex_start = req[54];
    valindex_sum = req[55];

    msg[55] = req[54];
    msg[56] = req[55];

    msg[13] = 0x01; // datacmd
    msg[14] = 0x01; // res

    cfg_pu_t *south_pu = g_cfg->g_coll_link;
    while (south_pu)
    {
        LOG_D("swj", "portname--->>> %s", south_pu->name);

        if (0 != strcmp(south_pu->name, portname))
        {
            south_pu = south_pu->next;
            continue;
        }

        cfg_su_t *dev = south_pu->su;
        while (dev)
        {
            if (0 != strcmp(dev->name, devname))
            {
                dev = dev->next;
                continue;
            }

            if (dev->loop <= 1)
            {
                for (i = 0; i < dev->valcntsum; i++)
                {
                    cfg_ch_t *ch = dev->ch + i;
                    cfg_node_t *node = ch->node;

                    for (j=0;j<18;j++)
                    {
                        if (j < strlen(node->data_name))
                            msg[msg_length++] = node->data_name[j];
                        else
                            msg[msg_length++] = 0x00; // '\0'
                    }
                    // data 41  8C  E8  EE

                    float value = ch->data;
                    unsigned char hex_array[4];

                    float_to_hex(value, hex_array);

                    msg[msg_length++] = hex_array[0];
                    msg[msg_length++] = hex_array[1];
                    msg[msg_length++] = hex_array[2];
                    msg[msg_length++] = hex_array[3];
                }
            }
            else
            {
                cfg_subdev_t *subdev = dev->subdev_list;
                while (subdev)
                {
                    for (i = 0; i < subdev->valcntsum; i++)
                    {
                        cfg_ch_t *ch = subdev->ch + i;
                        cfg_node_t *node = ch->node;

                        for (j = 0; j < 18; j++)
                        {
                            if (j < strlen(node->data_name))
                                msg[msg_length++] = node->data_name[j];
                            else
                                msg[msg_length++] = 0x00; // '\0'
                        }
                        // data 41  8C  E8  EE

                        float value = ch->data;
                        unsigned char hex_array[4];

                        float_to_hex(value, hex_array);

                        msg[msg_length++] = hex_array[0];
                        msg[msg_length++] = hex_array[1];
                        msg[msg_length++] = hex_array[2];
                        msg[msg_length++] = hex_array[3];
                    }
                    subdev = subdev->next;
                }
            }

            dev = dev->next;
        }
        south_pu = south_pu->next;
    }

    size = msg_length - 13;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int set_macaddr(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg)
{
    char macAddr[6];
    char mac1[32] = "";
    int msg_length = 13;
    int size = 9;
    int i = 0;
    int result = 0;
    uint8_t checkResult = 0;
    if (nlen < 21)
    {
        result = -1;
    }
    else
    {
        for (i = 0; i < 6; ++i)
        {
            macAddr[i] = req[14 + i];
        }
        result = set_local_mac("eth0", macAddr);
    }
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    msg[msg_length++] = 0x01;
    if (result > 0)
        msg[msg_length++] = 0x01;
    else
        msg[msg_length++] = 0x00;
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_sn(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 33;
    int i = 0;

    char *pStr_SN = g_cfg->g_basic->serial_no;

    int snLen = strlen(pStr_SN);
    uint8_t checkResult = 0;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    // data_cmd
    msg[msg_length++] = 0x00;
    // SN
    if (snLen > 32)
    {
        for (i = 0; i < 32; i++)
        {
            msg[msg_length++] = pStr_SN[i];
        }
    }
    else
    {
        for (i = 0; i < snLen; i++)
        {
            msg[msg_length++] = pStr_SN[i];
        }
        for (i = snLen; i < 32; ++i)
        {
            msg[msg_length++] = '\0';
        }
    }
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    return tcps_write(pu, ctx, msg, msg_length);
}

/**
 * Name:    cfg_create_root
 * Brief:   生成json文件的root根节点,以防重复打开关闭文件
 * Input:
 *  @json_buf:     json文件路径
 * Output:  cJSON--解析正确,NULL--解析错误
 */
static cJSON *cJSON_create_root(const char *json_buf)
{
    cJSON *root = cJSON_Parse(json_buf);
    if (root == NULL)
    {
        LOG_E("cfg", "json parsing dtu cfg null\n");
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL)
        {
            LOG_E("cfg", "Error before: %s\n", error_ptr);
        }
        return NULL;
    }

    return root;
}

static int set_default_sn(char *SN, char *filename)
{
    // 读取ANet-1E1SHJ.json文件
    char *cfg_buf = (char *)util_file_read(filename);
    if (cfg_buf == NULL)
    {
        return -1;
    }

    // 获取json的根节点
    cJSON *root = cJSON_create_root(cfg_buf);
    if (root == NULL)
    {
        return -1;
    }
    cJSON *basic = cJSON_GetObjectItem(root, "basic");
    if (basic == NULL)
    {
        return -1;
    }
    cJSON *sys = cJSON_GetObjectItem(basic, "system");
    if (sys == NULL)
    {
        return -1;
    }

    cJSON_ReplaceItemInObject(sys, "SN", cJSON_CreateString((char *)SN));

    FILE *file = fopen(filename, "w+");
    char *dtu = cJSON_Print(root);
    fwrite(dtu, 1, strlen(dtu), file);
    fclose(file);
    free(dtu);
    cJSON_Delete(root);
}

static int set_sn(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg)
{
    // if (nlen < 47)
    //     return -1;
    // int msg_length = 13;
    // int size = 2;
    // int i = 0;
    // int result = 0;
    // uint8_t checkResult = 0;

    // uint8_t buff_sn[64] = {0};
    // memset(buff_sn, 0, sizeof(buff_sn));
    // for (i = 0; i < 14; i++)
    // {
    //     buff_sn[i] = req[i + 14];
    // }

    // cJSON *basic = cJSON_GetObjectItem(g_cfg->dcfg, "basic");
    // cJSON *sys = cJSON_GetObjectItem(basic, "system");
    // cJSON_ReplaceItemInObject(sys, "SN", cJSON_CreateString((char *)buff_sn));

    // // fresh  --- ANet-1E1SHJ & ANet-1E2SHJ  --- ...

    // set_default_sn((char *)buff_sn, "./cfg/ANet-1E1SHJ-4G");
    // set_default_sn((char *)buff_sn, "./cfg/ANet-1E1SHJ-4GLR");

    // set_default_sn((char *)buff_sn, "./cfg/ANet-1E2SHJ-4G");
    // set_default_sn((char *)buff_sn, "./cfg/ANet-1E2SHJ-4GLR");

    // // fresh --- frpc.ini ---
    // util_cfg_ini_set("common", "user", (char *)buff_sn, "./frpc.ini");

    // // fresh --- dtu.json ---
    // FILE *file = fopen("./cfg/dtu.json", "w+");
    // char *dtu = cJSON_Print(g_cfg->dcfg);
    // fwrite(dtu, 1, strlen(dtu), file);
    // fclose(file);
    // free(dtu);

    // msg[11] = size >> 8;
    // msg[12] = size & 0xFF;
    // msg[msg_length++] = 0x01;
    // msg[msg_length++] = 0x01;
    // checkResult = checksum(msg, msg_length);
    // msg[msg_length++] = checkResult;
    // // util_hex_print(msg, msg_length);
    // return tcps_write(pu, ctx, msg, msg_length);
}

static int get_devtype(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 33;
    int i = 0;
    uint8_t checkResult = 0;

    char *type = g_cfg->g_basic->product;
    int snLen = strlen(type);
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    // data_cmd
    msg[msg_length++] = 0x00;
    // typename
    for (i = 0; i < snLen; i++)
    {
        msg[msg_length++] = type[i];
    }
    for (i = snLen; i < 32; ++i)
    {
        msg[msg_length++] = '\0';
    }
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    return tcps_write(pu, ctx, msg, msg_length);
}

static int set_devtype(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg)
{
    // if (nlen < 47)
    //     return -1;

    // int res = 1;
    // int msg_length = 13;
    // int size = 2;
    // int snLen = strlen(g_cfg->g_basic->product);
    // uint8_t checkResult = 0;

    // uint8_t buff_type[64] = {0};
    // memset(buff_type, 0, sizeof(buff_type));
    // int i;
    // for (i = 0; i < 11; i++)
    // {
    //     buff_type[i] = req[i + 14];
    // }

    // // printf("buff_type===>>>%s\n",buff_type);
    // // ANet-1E1SHJ
    // if (0 == strcmp((char *)buff_type, "ANet-1E1SHJ-4G"))
    // {
    //     system("cp ./cfg/ANet-1E1SHJ-4G.json ./cfg/dtu.json");
    // }
    // else if (0 == strcmp((char *)buff_type, "ANet-1E1SHJ-4G/LR"))
    // {
    //     system("cp ./cfg/ANet-1E1SHJ-4GLR.json ./cfg/dtu.json");
    // }
    // else if (0 == strcmp((char *)buff_type, "ANet-1E2SHJ-4G"))
    // {
    //     system("cp ./cfg/ANet-1E2SHJ-4G.json ./cfg/dtu.json");
    // }
    // else if (0 == strcmp((char *)buff_type, "ANet-1E2SHJ-4G/LR"))
    // {
    //     system("cp ./cfg/ANet-1E2SHJ-4GLR.json ./cfg/dtu.json");
    // }
    // else
    // {
    //     res = 0;
    // }

    // msg[11] = size >> 8;
    // msg[12] = size & 0xFF;
    // // data_cmd
    // msg[msg_length++] = 0x01;
    // // res
    // if (res)
    // {
    //     cJSON *basic = cJSON_GetObjectItem(g_cfg->dcfg, "basic");
    //     cJSON *sys = cJSON_GetObjectItem(basic, "system");
    //     cJSON_ReplaceItemInObject(sys, "model", cJSON_CreateString((char *)buff_type));
    //     msg[msg_length++] = 0x01;
    // }
    // else
    // {
    //     msg[msg_length++] = 0x00;
    // }

    // checkResult = checksum(msg, msg_length);
    // msg[msg_length++] = checkResult;
    // // util_hex_print(msg, msg_length);
    // return tcps_write(pu, ctx, msg, msg_length);
}

static int enter_test_mode(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 1;
    int i = 0;
    int snLen = strlen(g_cfg->g_basic->product);
    uint8_t checkResult = 0;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    // data_cmd
    msg[msg_length++] = 0x01;
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;
    // util_hex_print(msg, msg_length);
    auto_start();
    return tcps_write(pu, ctx, msg, msg_length);
}

static int exit_test_mode(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 1;
    int i = 0;
    int snLen = strlen(g_cfg->g_basic->product);
    uint8_t checkResult = 0;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    // data_cmd
    msg[msg_length++] = 0x01;
    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    // util_hex_print(msg, msg_length);
    auto_stop();
    return tcps_write(pu, ctx, msg, msg_length);
}

static int set_do(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msgStr)
{
    // if (nlen < 16)
    //     return -1;
    // int i = 0;
    // int result = 0;
    // uint8_t checkResult = 0;

    // api_t *api = (api_t *)pu->hanlder.api;
    // int do_val = req[13]; // 0断开 1闭合 2切换
    // int do_chan = req[14];
    // char buff_val[10] = "";
    // char portName[10] = {0};
    // sprintf(buff_val, "%d", do_val);
    // sprintf(portName, "do%d", do_chan);

    // // rb_mem_t *mem = api->get_g_rb_mem("gateway", "GSMState");
    // rb_mem_t *mem = api->get_g_rb_mem("gateway", portName);
    // if (mem == NULL)
    // {
    //     UTIL_LOG_E(pu, "find rbmem:%s NULL", portName);
    //     return -1;
    // }

    // msg_t msg;
    // msg.type = MSG_TYPE_CTRL;
    // msg.ts = util_hw_get_systs();
    // msg.su = mem->su->name;
    // msg.ch = mem->ch->name;

    // kv_t push;
    // memset(&push, 0, sizeof(kv_t));
    // strcpy(push.key, msg.ch);
    // strcpy(push.value, buff_val);
    // msg.value = (void *)&push;

    // UTIL_LOG_I(pu, "ctrl key:%s,value:%s---->", push.key, buff_val);
    // dlmodule_t *dlmodule = (dlmodule_t *)mem->pu->hanlder.dlmodule;
    // int ret = dlmodule->msg(mem->pu, &msg);

    // if (ret == 0)
    // {
    //     UTIL_LOG_I(pu, "ctrl key:%s,value:%s OK!", push.key, push.value);
    // }
    // else
    // {
    //     UTIL_LOG_E(pu, "ctrl key:%s,value:%s error!", push.key, push.value);
    // }
    return 0;
}

static int get_topo(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 16;
    int size = 0;
    uint8_t checkResult = 0;

    LOG_W("SWJ", "----------------get topology-------------\n");

    msg[13] = 0x00; // datacmd
    msg[14] = 0x01; // res

    // portsum  -1-
    // portname -20*portsum-

    uint8_t devsumlist[20] = {0};

    int i;

    cfg_pu_t *south_pu = g_cfg->g_coll_link;
    int portsum = 0;
    while (south_pu)
    {
        LOG_D("swj", "portname--->>> %s", south_pu->name);

        for (i = 0; i < 20; i++)
        {
            if (i < strlen(south_pu->name))
            {
                msg[msg_length++] = south_pu->name[i]; // portname start from 16
            }
            else
            {
                msg[msg_length++] = 0x00;
            }
        }

        if (0 == strcmp(south_pu->name, "rs485_1"))
        {
            devsumlist[0] = south_pu->devsumlist;
        }
        else if (0 == strcmp(south_pu->name, "rs485_2"))
        {
            devsumlist[1] = south_pu->devsumlist;
        }
        else if (0 == strcmp(south_pu->name, "rs485_3"))
        {
            devsumlist[2] = south_pu->devsumlist;
        }
        else if (0 == strcmp(south_pu->name, "rs485_4"))
        {
            devsumlist[3] = south_pu->devsumlist;
        }
        else if (0 == strcmp(south_pu->name, "rs485_5"))
        {
            devsumlist[4] = south_pu->devsumlist;
        }
        else if (0 == strcmp(south_pu->name, "rs485_6"))
        {
            devsumlist[5] = south_pu->devsumlist;
        }
        else if (0 == strcmp(south_pu->name, "rs485_7"))
        {
            devsumlist[6] = south_pu->devsumlist;
        }
        else if (0 == strcmp(south_pu->name, "rs485_8"))
        {
            devsumlist[7] = south_pu->devsumlist;
        }

        portsum++;
        south_pu = south_pu->next;
    }

    msg[15] = portsum; // portsum  done

    for (i = 0; i < 20; i++)
    {
        msg[msg_length++] = devsumlist[i]; // devsumlist
    }

    south_pu = g_cfg->g_coll_link;
    while (south_pu)
    {
        cfg_su_t *dev = south_pu->su;
        while (dev)
        {
            for (i = 0; i < 20; i++)
            {
                if (i < strlen(dev->name))
                {
                    msg[msg_length++] = dev->name[i];
                }
                else
                {
                    msg[msg_length++] = 0x00;
                }
            }
            dev = dev->next;
        }
        south_pu = south_pu->next;
    }

    size = msg_length - 13;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_trans_state(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 16;
    int size = 0;
    uint8_t checkResult = 0;

    uint8_t portsum = 0;

    LOG_W("SWJ", "----------------get trans state-------------\n");

    msg[13] = 0x00; // datacmd
    msg[14] = 0x01; // res

    cfg_pu_t *nor_pu = g_cfg->g_trans_link;
    while (nor_pu)
    {
        portsum++;

        msg[msg_length++] = nor_pu->id; // coll pu id
        msg[msg_length++] = 1;          // coll pu state

        msg[msg_length++] = nor_pu->pkg_send >> 24;
        msg[msg_length++] = nor_pu->pkg_send >> 16;
        msg[msg_length++] = nor_pu->pkg_send >> 8;
        msg[msg_length++] = nor_pu->pkg_send & 0xFF;

        msg[msg_length++] = nor_pu->pkg_recv >> 24;
        msg[msg_length++] = nor_pu->pkg_recv >> 16;
        msg[msg_length++] = nor_pu->pkg_recv >> 8;
        msg[msg_length++] = nor_pu->pkg_recv & 0xFF;

        msg[msg_length++] = 0x04;
        msg[msg_length++] = 0x0A;
        msg[msg_length++] = 0x0C;
        msg[msg_length++] = 0x03;
        msg[msg_length++] = 0x00;

        nor_pu = nor_pu->next;
    }

    msg[15] = portsum; // coll pu sum

    size = msg_length - 13;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_collect_state(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 16;
    int size = 0;
    uint8_t checkResult = 0;

    uint8_t portsum = 0;

    LOG_W("SWJ", "----------------get collection state-------------\n");

    msg[13] = 0x00; // datacmd
    msg[14] = 0x01; // res

    cfg_pu_t *south_pu = g_cfg->g_coll_link;
    while (south_pu)
    {
        portsum++;

        msg[msg_length++] = south_pu->id; // coll pu id

        msg[msg_length++] = south_pu->pkg_send >> 24;
        msg[msg_length++] = south_pu->pkg_send >> 16;
        msg[msg_length++] = south_pu->pkg_send >> 8;
        msg[msg_length++] = south_pu->pkg_send & 0xFF;

        msg[msg_length++] = south_pu->pkg_recv >> 24;
        msg[msg_length++] = south_pu->pkg_recv >> 16;
        msg[msg_length++] = south_pu->pkg_recv >> 8;
        msg[msg_length++] = south_pu->pkg_recv & 0xFF;

        south_pu = south_pu->next;
    }

    msg[15] = portsum; // coll pu sum

    size = msg_length - 13;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_dev_status(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 16;
    int size = 0;
    uint8_t checkResult = 0;

    LOG_W("SWJ", "----------------get device status-------------\n");

    msg[13] = 0x00; // datacmd
    msg[14] = 0x01; // res

    uint16_t devsum = 0;

    int i;

    cfg_pu_t *south_pu = g_cfg->g_coll_link;
    while (south_pu)
    {
        LOG_D("swj", "portname--->>> %s", south_pu->name);

        cfg_su_t *dev = south_pu->su;

        while (dev)
        {
            if (dev->state == 1)
                msg[msg_length++] = 1;
            else
                msg[msg_length++] = 0;

            msg[msg_length++] = dev->valcntsum & 0xFF;

            dev = dev->next;
        }

        devsum += south_pu->devsumlist;
        south_pu = south_pu->next;
    }

    msg[15] = devsum;

    size = msg_length - 13;
    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int sys_reboot(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    int msg_length = 13;
    int size = 38;
    uint8_t checkResult = 0;

    LOG_W("SWJ", "----------------reboot-------------\n");

    msg[12] = 0x02;           // datalen
    msg[msg_length++] = 0x00; // datacmd
    msg[msg_length++] = 0x01; // res

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_dio_ai(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    // int msg_length = 13;
    // int size = 38;
    // uint8_t checkResult = 0;
    // int i = 0;
    // int64_t valInt = 0;
    // uint8_t DI[2] = {0};
    // uint8_t DO[2] = {0};
    // float AI[8] = {0};
    // api_t *api = (api_t *)pu->hanlder.api;
    // char portName[10] = {0};

    // double ai_val = 0;
    // int64_t dio_val = 0;

    // for (i = 0; i < 6; i++)
    // {
    //     sprintf(portName, "di%d", i + 1);
    //     rb_mem_t *mem_di = api->get_g_rb_mem("gateway", portName);
    //     if (NULL == mem_di)
    //     {
    //         DI[i] = 0;
    //         continue;
    //     }
    //     util_ch_get_integer_val(mem_di->ch, &dio_val);
    //     DI[1] |= (dio_val << i);
    // }
    // for (i = 0; i < 4; i++)
    // {
    //     sprintf(portName, "do%d", i + 1);
    //     rb_mem_t *mem_do = api->get_rb_mem(pu, "gateway", portName);
    //     if (NULL == mem_do)
    //     {
    //         DO[i] = 0;
    //         continue;
    //     }
    //     util_ch_get_integer_val(mem_do->ch, &dio_val);
    //     DO[1] |= (dio_val << i);
    // }
    // for (i = 0; i < 8; ++i)
    // {
    //     AI[i] = 0.0;
    // }
    // msg[11] = size >> 8;
    // msg[12] = size & 0xFF;
    // // data_cmd
    // msg[msg_length++] = 0x00;
    // // res
    // msg[msg_length++] = 0x01;
    // // DI
    // for (i = 0; i < 2; i++)
    // {
    //     msg[msg_length++] = DI[i];
    // }
    // // DO
    // for (i = 0; i < 2; i++)
    // {
    //     msg[msg_length++] = DO[i];
    // }
    // // AI
    // for (i = 0; i < 8; i++)
    // {
    //     memcpy(msg + msg_length, &AI[i], 4);
    //     msg_length += 4;
    // }
    // checkResult = checksum(msg, msg_length);
    // msg[msg_length++] = checkResult;
    // // AA BB 55 00 01 00 00 00 00 00 0B 00 26
    // // 00 01
    // // 01 00
    // // 00 01
    // //  00 00 00 00
    // //  00 00 00 00
    // //  00 00 00 00
    // //  00 00 00 00
    // //  00 00 00 00
    // //  00 00 00 00
    // //  00 00 00 00
    // //  00 00 00 00 EF
    // // util_hex_print(msg, msg_length);
    // return tcps_write(pu, ctx, msg, msg_length);
}

int is_valid_json(const char *json_str)
{
    cJSON *json = cJSON_Parse(json_str);
    if (json == NULL)
    {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL)
        {
            fprintf(stderr, "Invalid JSON format before: %s\n", error_ptr);
        }
        return 0; // 不是有效的JSON
    }

    cJSON_Delete(json);
    return 1; // 是有效的JSON
}

static int recv_file_data(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg, char *filename)
{
    LOG_W("SWJ", "CMD2===============>>> %s", filename);

    int datalen = word2Int(req + 11); // 0x01 0x27
    int datacmd = req[13];

    if (datalen <= 3)
        return -1;
    if (datacmd != 2)
        return -1;

    // 00 01 总包数量
    // 00 01 包序号
    uint16_t total_pkgs = word2Int(req + 14);
    uint16_t pkg_sn = word2Int(req + 16);

    if (total_pkgs > 1)
    {
        LOG_E("swj", "暂不支持分包....");
        return -1;
    }

    // FIXME: 暂时不考虑分包
    uint32_t filecontent_size = datalen - 5;

    char buffer[1024] = {0};
    int i;
    for (i = 0; i < filecontent_size; i++)
    {
        buffer[i] = req[18 + i];
    }

    FILE *file = NULL;
    if (strstr(filename, ".json") != NULL)
    {
        if (is_valid_json(buffer))
        {
            LOG_I("SWJ", "The string is valid JSON.\n");
        }
        else
        {
            LOG_E("SWJ", "The string is NOT valid JSON.\n");
            return -1;
        }

        if (0 == strcmp(filename, "SYS.json"))
        {
            file = fopen(GW_CFG_SYS, "w+");
        }
        else if (0 == strcmp(filename, "CLT.json"))
        {
            file = fopen(GW_CFG_CLT, "w+");
        }
        else if (0 == strcmp(filename, "RULE.json"))
        {
            file = fopen(GW_CFG_RULE, "w+");
        }
        else if (0 == strcmp(filename, "AUTOPROBE.json"))
        {
            file = fopen(GW_CFG_AUTOPROBE, "w+");
        }
    }
    else
    {
        char template_path[100] = "";
        sprintf(template_path, "./cfg/template/south/%s", filename);
        file = fopen(template_path, "w+");
    }

    if (file == NULL)
    {
        printf("Failed to open file\n");
        return -1;
    }

    // printf("buffer===>> %s\n",buffer);

    fwrite(buffer, 1, strlen(buffer), file);

    fclose(file);

    int size = 6;
    uint8_t checkResult = 0;

    msg[8] = 0x08;

    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    msg[13] = datacmd + 1;

    msg[14] = 0x00;
    msg[15] = 0x01;
    msg[16] = 0x00;
    msg[17] = 0x01;

    msg[18] = 0x01; // res

    checkResult = checksum(msg, 19);
    msg[19] = checkResult;

    return tcps_write(pu, ctx, msg, 20);
}

static int reply_file_cmd0(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg, char *name)
{
    // [AA][BB][55][00][01]
    // [00][00][00][00][00]
    // [50][00][0B][00][00][08][53][59][53][2E][6A][73][6F][6E][05]

    int datalen = word2Int(req + 11);
    int datacmd = req[13];

    if (datalen <= 3)
        return -1;

    if (datacmd == 2) // dataCmd 2: recv file buff from swj
        return -1;

    int filename_len = word2Int(req + 14);
    uint32_t filecontent_size = 0;

    char filename[50] = {0};
    int i;
    for (i = 0; i < filename_len; i++)
    {
        filename[i] = req[16 + i];
    }

    printf("filename-XYZ-XXX-->>> %s\n", filename);

    char *cfg_buff = NULL;

    if (0 == strncmp(filename, "SYS.json", 8))
    {
        cfg_buff = (char *)util_file_read(GW_CFG_SYS);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ config file SYS.json!\n");
            return -1;
        }
    }
    else if (0 == strncmp(filename, "CLT.json", 8))
    {
        cfg_buff = (char *)util_file_read(GW_CFG_CLT);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ config file CLT.json!\n");
            return -1;
        }
    }
    else if (0 == strncmp(filename, "RULE.json", 9))
    {
        cfg_buff = (char *)util_file_read(GW_CFG_RULE);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ config file RULE.json!\n");
            return -1;
        }
    }
    else if (0 == strncmp(filename, "AUTOPROBE.json", 14))
    {
        cfg_buff = (char *)util_file_read(GW_CFG_AUTOPROBE);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ config AUTOPROBE.json!\n");
            return -1;
        }
    }
    else // template
    {
        char template_path[100] = "";
        sprintf(template_path, "./cfg/template/south/%s", filename);

        if (access(template_path, F_OK) == -1)
        {
            LOG_E("cfg", "Failed to FIND config file %s!\n", filename);
            return -1;
        }

        cfg_buff = (char *)util_file_read(template_path);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ template %s!\n", filename);
            return -1;
        }
    }

    if (NULL == cfg_buff)
        return -1;

    strcpy(name, filename);
    filecontent_size = strlen(cfg_buff);

    // aa bb 55 00 01 00 00 00 08
    // 00 50
    // 00 10
    // 01 (data_cmd:1-主动获取响应; 3-发送文件响应; 5-主动发送响应)
    // 00 08
    // 53 59 53 2e 6a 73 6f 6e 00 00 02 a1 01 b7

    int size = filename_len + 8; // 文件名称长度
    uint8_t checkResult = 0;

    msg[8] = 0x08;

    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    msg[13] = 1; // 0,4 --> 1,5

    msg[14] = filename_len >> 8;
    msg[15] = filename_len & 0xFF;

    for (i = 0; i < filename_len; i++)
    {
        msg[16 + i] = filename[i];
    }
    int msg_length = 16 + filename_len;

    msg[msg_length++] = filecontent_size >> 24;
    msg[msg_length++] = filecontent_size >> 16;
    msg[msg_length++] = filecontent_size >> 8;
    msg[msg_length++] = filecontent_size & 0xFF;

    msg[msg_length++] = 0x01; // res

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int reply_file_cmd4(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg, char *filenamebuff)
{
    int datalen = word2Int(req + 11);
    int datacmd = req[13];

    if (datalen <= 3)
        return -1;

    if (datacmd != 4)
        return -1;

    int filename_len = word2Int(req + 14);
    uint32_t filecontent_size = 0;

    memset(filenamebuff, 0, sizeof(filenamebuff));
    int i;
    for (i = 0; i < filename_len; i++)
    {
        filenamebuff[i] = req[16 + i];
    }
    filenamebuff[i] = '\0'; // memset不生效 故添加此行代码

    printf("-DataCmd4-filename->>> %s\n", filenamebuff);

    int size = filename_len + 8; // 文件名称长度
    uint8_t checkResult = 0;

    msg[8] = 0x08;

    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    msg[13] = 0x05; // datacmd

    msg[14] = filename_len >> 8;
    msg[15] = filename_len & 0xFF;

    for (i = 0; i < filename_len; i++)
    {
        msg[16 + i] = filenamebuff[i];
    }
    int msg_length = 16 + filename_len;

    msg[msg_length++] = 0x01; // res

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int reply_file_data(cfg_pu_t *pu, tcps_t *ctx, uint8_t *req, int nlen, uint8_t *msg, char *filename)
{
    char *cfg_buff = NULL;

    if (0 == strcmp(filename, "SYS.json"))
    {
        cfg_buff = (char *)util_file_read(GW_CFG_SYS);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ config file SYS.json!\n");
            return -1;
        }
    }
    else if (0 == strcmp(filename, "CLT.json"))
    {
        cfg_buff = (char *)util_file_read(GW_CFG_CLT);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ config file CLT.json!\n");
            return -1;
        }
    }
    else if (0 == strcmp(filename, "RULE.json"))
    {
        cfg_buff = (char *)util_file_read(GW_CFG_RULE);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ config file RULE.json!\n");
            return -1;
        }
    }
    else if (0 == strcmp(filename, "AUTOPROBE.json"))
    {
        cfg_buff = (char *)util_file_read(GW_CFG_AUTOPROBE);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ config AUTOPROBE.json!\n");
            return -1;
        }
    }
    else // template
    {
        char template_path[100] = "";
        sprintf(template_path, "./cfg/template/south/%s", filename);

        if (access(template_path, F_OK) == -1)
        {
            LOG_E("cfg", "Failed to FIND config file %s!\n", filename);
            return -1;
        }

        cfg_buff = (char *)util_file_read(template_path);
        if (cfg_buff == NULL)
        {
            LOG_E("cfg", "Failed to READ template %s!\n", filename);
            return -1;
        }
    }

    if (NULL == cfg_buff)
        return -1;

    uint8_t checkResult = 0;
    msg[8] = 0x04;

    int filelen = strlen(cfg_buff);
    int size = filelen + 5;

    msg[11] = size >> 8;
    msg[12] = size & 0xFF;
    msg[13] = 0x02; // data_cmd
    msg[14] = 0x00;
    msg[15] = 0x01;
    msg[16] = 0x00;
    msg[17] = 0x01;

    int i;
    for (i = 0; i < filelen; i++)
    {
        msg[18 + i] = cfg_buff[i];
    }
    int msg_length = 18 + filelen;

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    // fenbao ...

    return tcps_write(pu, ctx, msg, msg_length);
}

#define IS_CSV_FILE(mode) (((mode) & S_IFMT) == S_IFREG) && \
                              (strcasecmp("csv", strrchr((file_name), '.') + 1) == 0)

void list_csv_files(const char *directory)
{
    struct dirent *entry;
    DIR *dp;
    struct stat statbuf;

    dp = opendir(directory);
    if (dp == NULL)
    {
        perror("opendir");
        exit(EXIT_FAILURE);
    }

    while ((entry = readdir(dp)))
    {
        char path[256];
        char *file_name = entry->d_name;

        if (strcmp(file_name, ".") == 0 || strcmp(file_name, "..") == 0)
            continue;

        snprintf(path, sizeof(path), "%s/%s", directory, file_name);

        if (stat(path, &statbuf) == -1)
        {
            perror("stat");
            continue;
        }

        if (IS_CSV_FILE(statbuf.st_mode))
        {
            printf("==============>>>> Found CSV file: %s\n", path);
        }
    }

    closedir(dp);
}

static int get_file_info(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{

    const char *directory = "./cfg/template/south"; // 修改为你的目录路径
    list_csv_files(directory);

    // aa bb 55 00 01 00 00 00 08 00  40   00 02 00 00 05
    int msg_length = 13;
    int size = 2; // datalen
    uint8_t checkResult = 0;

    msg[8] = 0x08; // gw reply

    msg[11] = size >> 8;
    msg[12] = size & 0xFF;

    msg[msg_length++] = 0x00; // datacmd
    msg[msg_length++] = 0x01; // template quantity

    char *filename = "AEW100.csv";
    int filenam_len = strlen(filename);
    msg[msg_length++] = filenam_len; // strlen AEW100.csv

    int i;
    for (i = 0; i < filenam_len; i++)
    {
        msg[msg_length++] = filename[i];
    }

    checkResult = checksum(msg, msg_length);
    msg[msg_length++] = checkResult;

    return tcps_write(pu, ctx, msg, msg_length);
}

static int get_net_state(cfg_pu_t *pu, tcps_t *ctx, uint8_t *msg)
{
    // int msg_length = 13;
    // int size = 100;
    // int i = 0;
    // uint8_t checkResult = 0;
    // char str[32];
    // int len = 0;
    // api_t *api = (api_t *)pu->hanlder.api;
    // int64_t state_4G = 0;
    // rb_mem_t *mem = api->get_g_rb_mem("gateway", "GSMState");
    // if (NULL == mem)
    // {
    //     state_4G = -1;
    // }
    // else
    // {
    //     util_ch_get_integer_val(mem->ch, &state_4G);
    // }
    // memset(str, sizeof(str), 0);
    // if (state_4G >= 0 && state_4G < 5)
    //     strcpy(str, GSMState_Table[state_4G]);
    // else
    //     strcpy(str, "error");
    // msg[11] = size >> 8;
    // msg[12] = size & 0xFF;
    // // data_cmd
    // msg[msg_length++] = 0x00;
    // // res
    // msg[msg_length++] = 0x01;
    // // 4g_num
    // msg[msg_length++] = state_4G;
    // // wifi_num
    // msg[msg_length++] = 0x00;
    // // 4g_state
    // len = strlen(str);
    // if (len >= 24)
    // {
    //     for (i = 0; i < 24; i++)
    //     {
    //         msg[msg_length++] = str[i];
    //     }
    // }
    // else
    // {
    //     for (i = 0; i < len; i++)
    //     {
    //         msg[msg_length++] = str[i];
    //     }
    //     for (i = len; i < 24; i++)
    //     {
    //         msg[msg_length++] = '\0';
    //     }
    // }
    // for (i = 0; i < 72; i++)
    // {
    //     msg[msg_length++] = '\0';
    // }
    // checkResult = checksum(msg, msg_length);
    // msg[msg_length++] = checkResult;
    // // util_hex_print(msg, msg_length);
    // return tcps_write(pu, ctx, msg, msg_length);
}

int tcps_write(cfg_pu_t *pu, tcps_t *ctx, uint8_t *buf, int len)
{
    if (ctx->s == -1)
    {
        // printf("%s.%d socket -1\n",ctx->pu->name,ctx->slave);
        return -1;
    }

    if (ctx->debug)
    {
        int i;
        for (i = 0; i < len; i++)
            printf("<%.2X>", buf[i]);
        printf("\n\n");
    }

    ctx->len = 0;

    return write(ctx->s, buf, len);
}
